/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.sgf.dt.provider.common;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataProject;
import com.inspur.edp.lcm.metadata.api.service.FileService;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.NoCodeService;
import com.inspur.edp.sgf.api.common.ResourceType;
import com.inspur.edp.sgf.api.entity.ServiceDefine;
import com.inspur.edp.sgf.api.entity.ServiceOperation;
import com.inspur.edp.sgf.api.entity.ServiceParameter;
import com.inspur.edp.sgf.api.entity.SgMetadata;
import com.inspur.edp.sgf.api.entity.SgModel;
import com.inspur.edp.sgf.api.utils.ObjectMapperUtil;
import com.inspur.edp.sgf.dt.provider.utils.MetadataUtils;
import com.inspur.edp.sgf.provider.vo.utils.SimpleViewModelUtils;
import com.inspur.edp.sgf.provider.vo.utils.ViewModelUtils;
import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * 功能描述: @ClassName: EapiBuilder @Author: Fynn Qi @Date: 2020/12/24 9:17 @Version: V1.0
 */
public class EapiBuilder {

    private final String EAPI_RESOURCE_TYPE_VO = "VO";
    private final String EAPI_RESOURCE_TYPE_VO_SIMPLE = "VO-Simple";
    private final String EAPI_TYPE_NAME = "ExternalApi";
    private final String EAPI_SUFFIX_NAME = ".eapi";
    private final String EAPI_PATH = "/eapi";
    private ResourceType resourceType;

    public GspMetadata updateEapi(String eapiMetadataId, GspMetadata voMetadata, ResourceType resourceType) {
        this.resourceType = resourceType;
        NoCodeService noCodeService = SpringBeanUtils.getBean(NoCodeService.class);
        GspMetadata metadata = noCodeService.getMetadata(eapiMetadataId);
        //构造Header
        metadata.setHeader(updateMetadataHeader(voMetadata, metadata));
        //构造Content
        metadata.setContent(buildEapiMetadataDefine(voMetadata, metadata));
        //构造扩展属性
        ObjectNode extension = getEapiMetadataExtendProperties(metadata);
        metadata.setExtendProperty(ObjectMapperUtil.serialize(extension));
        noCodeService.saveMetadata(metadata);
        return metadata;
    }

    private ObjectNode getEapiMetadataExtendProperties(GspMetadata metadata) {
        ObjectNode node = ObjectMapperUtil.getMapper().createObjectNode();
        node.put("metadataVersion", UUID.randomUUID().toString());
        node.put("resourceType", ((SgMetadata) metadata.getContent()).getService().getResourceType());
        node.put("resourceId", ((SgMetadata) metadata.getContent()).getService().getResourceId());
        node.put("uri", ((SgMetadata) metadata.getContent()).getRouter());
        return node;
    }

    private MetadataHeader updateMetadataHeader(GspMetadata voMetadata, GspMetadata eapiMetadata) {
        //获取当前需要更新的运行时定制元数据的Header
        MetadataHeader header = eapiMetadata.getHeader();
        // 编号和名称取自运行时定制扩展的VO元数据，VO的编号和名称已作出对应的扩展调整
        header.setCode(voMetadata.getHeader().getCode());
        header.setName(voMetadata.getHeader().getName());
        // 是否允许扩展,与VO同步
        header.setExtendable(voMetadata.getHeader().isExtendable());
        return header;
    }

    public GspMetadata buildEapi(GspMetadata voMetadata, ResourceType resourceType) {
        this.resourceType = resourceType;
        GspMetadata metadata = new GspMetadata();
        // 初始化Header信息
        metadata.setHeader(buildEapiMetadataHeader(voMetadata));
        //构造Content
        metadata.setContent(buildEapiMetadataDefine(voMetadata, metadata));
        //构造扩展属性
        ObjectNode extension = getEapiMetadataExtendProperties(metadata);
        metadata.setExtendProperty(ObjectMapperUtil.serialize(extension));
        NoCodeService noCodeService = SpringBeanUtils.getBean(NoCodeService.class);
        noCodeService.saveMetadata(metadata);
        return metadata;
    }

    public GspMetadata buildEapi(GspMetadata voMetadata, String path, ResourceType resourceType) {
        this.resourceType = resourceType;
        // 初始化Header信息
        GspMetadata eapiMetadata = buildEapiMetadataBaseInfo(voMetadata, path);
        // 生成元数据content
        eapiMetadata = buildEapiMetadataFileContent(voMetadata, eapiMetadata);
        return eapiMetadata;
    }

    private GspMetadata buildEapiMetadataFileContent(GspMetadata voMetadata, GspMetadata eapiMetadata) {
        List<String> metadataTypeList = new ArrayList<>();
        metadataTypeList.add(EAPI_SUFFIX_NAME);
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
        String eapiRelativePath = eapiMetadata.getRelativePath();
        List<GspMetadata> metadataList = metadataService.getMetadataList(eapiRelativePath, metadataTypeList);
        if (metadataList != null && metadataList.size() > 0) {
            String metadataCode = eapiMetadata.getHeader().getCode();
            boolean exist = metadataList.stream().anyMatch(x -> metadataCode.equalsIgnoreCase(x.getHeader().getCode()));
            //如果不存在当前编号的EAPI元数据，则直接创建
            if (!exist) {
                // 元数据初始化
                eapiMetadata = metadataService.initializeMetadataEntity(eapiMetadata);
                // 创建元数据
                metadataService.createMetadata(eapiRelativePath, eapiMetadata);
            }
        } else {
            // 元数据初始化
            eapiMetadata = metadataService.initializeMetadataEntity(eapiMetadata);
            // 创建元数据
            metadataService.createMetadata(eapiRelativePath, eapiMetadata);
        }
        // 加载元数据
        eapiMetadata = metadataService.loadMetadata(eapiMetadata.getHeader().getFileName(), eapiRelativePath);
        // eapi赋值给元数据的content
        eapiMetadata.setContent(buildEapiMetadataDefine(voMetadata, eapiMetadata));
        // 保存元数据,元数据设置扩展属性
        ObjectNode extension = getEapiMetadataExtendProperties(eapiMetadata);
        eapiMetadata.setExtendProperty(ObjectMapperUtil.serialize(extension));
        // 元数据保存所需要的完整路径
        String fullPath = String.format("%s/%s%s", eapiRelativePath, eapiMetadata.getHeader().getCode(), EAPI_SUFFIX_NAME);
        metadataService.saveMetadata(eapiMetadata, fullPath);
        return eapiMetadata;
    }

    private SgMetadata buildEapiMetadataDefine(GspMetadata vo, GspMetadata eapiMetadata) {
        SgMetadata eapiContent = new SgMetadata();
        // 定义SG外部服务基本信息
        eapiContent.setId(eapiMetadata.getHeader().getId());
        eapiContent.setCode(eapiMetadata.getHeader().getCode());
        eapiContent.setName(eapiMetadata.getHeader().getName());
        eapiContent.setBizObject(eapiMetadata.getHeader().getBizobjectID());
        DevBasicBoInfo boInfo = MetadataUtils.getDevBasicBoInfo(eapiMetadata.getHeader().getBizobjectID());
        eapiContent.setCriticalApplication(boInfo.getAppCode().toLowerCase());
        eapiContent.setServiceUnit(boInfo.getSuCode().toLowerCase());
        String boCode = "";
        if (boInfo.getBoInfo() != null && StringUtils.isNotBlank(boInfo.getBoInfo().getCode())) {
            boCode = boInfo.getBoInfo().getCode();
        }
        //TODO 后续修改为下面的生成方式
        // route的默认生成方式：BO的编号_VO元数据的编号
        eapiContent.setRouteUrl(vo.getHeader().getCode().toLowerCase());
        //eapiContent.setRouteUrl(String.format("%s_%s", boCode.toLowerCase(), vo.getHeader().getCode().toLowerCase()));
        // 版本信息，默认1.0
        eapiContent.setVersion("1.0");
        eapiContent.setDescription(vo.getHeader().getCode() + "服务");
        // 生成服务定义
        eapiContent.setService(this.buildServiceDefine(vo));
        // 获取服务模型列表
        eapiContent.getModels().addAll(getServiceModels(eapiContent));
        return eapiContent;
    }

    private List<SgModel> getServiceModels(SgMetadata eapiContent) {
        List<SgModel> models = new ArrayList<>();
        Set<String> modelsIdsSet = new HashSet<>();
        if (eapiContent.getService().getOperations().size() <= 0) {
            return models;
        }
        for (ServiceOperation operation : eapiContent.getService().getOperations()) {
            if (operation.getParameters() == null || operation.getParameters().size() <= 0) {
                continue;
            }
            for (ServiceParameter parameter : operation.getParameters()) {
                if (parameter.isBasicType() || parameter.getRefId().equals("object") || parameter.getModelId().equals("object")) {
                    continue;
                }
                SgModel sgModel = getModelProperty(parameter);
                //判断eapi中是否已存在
                long count =
                        eapiContent.getModels().stream()
                                .filter(x -> x.getId().equalsIgnoreCase(sgModel.getId()))
                                .count();
                if (count <= 0) {
                    //判断本次models中是否已添加
                    if (!modelsIdsSet.contains(sgModel.getId())) {
                        models.add(sgModel);
                        modelsIdsSet.add(sgModel.getId());
                    }
                }
            }
        }
        return models;
    }

    private SgModel getModelProperty(ServiceParameter param) {
        SgModel sgModel = new SgModel();
        sgModel.setId(param.getRefId());
        sgModel.setCode(param.getRefCode());
        sgModel.setName(param.getRefName());
        sgModel.setModelId(param.getModelId());
        sgModel.setModelCode(param.getModelCode());
        sgModel.setModelName(param.getModelName());
        sgModel.setRelativePath(param.getRefPath());
        sgModel.setFileName(param.getRefFileName());
        sgModel.setModelType(param.getModelType());
        return sgModel;
    }

    private ServiceDefine buildServiceDefine(GspMetadata vo) {
        ServiceDefine serviceDefine = new ServiceDefine();
        serviceDefine.setId(UUID.randomUUID().toString());
        serviceDefine.setResourceId(vo.getHeader().getId());
        serviceDefine.setResourceType(getResourceType(resourceType));
        serviceDefine.setResourceCode(((GspViewModel) vo.getContent()).getGeneratedConfigID());
        serviceDefine.setResourceName(vo.getHeader().getName());
        serviceDefine.setOperations(new ArrayList<>());
        switch (resourceType) {
            case VO_ADVANCE:
                serviceDefine.getOperations().addAll(ViewModelUtils.getAllOperations(vo));
                break;
            case VO_SIMPLE:
                serviceDefine.getOperations().addAll(SimpleViewModelUtils.getAllOperations(vo));
                break;
            default:
                throw new RuntimeException("不支持的资源类型:" + resourceType);
        }
        return serviceDefine;
    }

    private MetadataHeader buildEapiMetadataHeader(GspMetadata vo) {
        MetadataHeader header = new MetadataHeader();
        header.setId(UUID.randomUUID().toString());
        header.setNameSpace(vo.getHeader().getNameSpace());
        header.setCode(vo.getHeader().getCode());
        header.setName(vo.getHeader().getName());
        header.setExtendable(vo.getHeader().isExtendable());
        if (StringUtils.isBlank(vo.getHeader().getBizobjectID())) {
            throw new RuntimeException(String.format("VO元数据【%s(ID:%s)】的业务对象不能为空", vo.getHeader().getCode(), vo.getHeader().getId()));
        }
        header.setBizobjectID(vo.getHeader().getBizobjectID());
        header.setType(EAPI_TYPE_NAME);

        return header;
    }

    private GspMetadata buildEapiMetadataBaseInfo(GspMetadata vo, String path) {
        GspMetadata metadata = new GspMetadata();
        metadata.setHeader(new MetadataHeader());
        metadata.getHeader().setNameSpace(vo.getHeader().getNameSpace());
        metadata.getHeader().setCode(vo.getHeader().getCode());
        metadata.getHeader().setName(vo.getHeader().getName());
        metadata.getHeader().setExtendable(vo.getHeader().isExtendable());
        if (StringUtils.isBlank(vo.getHeader().getBizobjectID())) {
            throw new RuntimeException(String.format("VO元数据【%s(ID:%s)】的业务对象不能为空", vo.getHeader().getCode(), vo.getHeader().getId()));
        }
        metadata.getHeader().setBizobjectID(vo.getHeader().getBizobjectID());
        metadata.getHeader().setType(EAPI_TYPE_NAME);
        metadata.getHeader().setFileName(vo.getHeader().getCode() + EAPI_SUFFIX_NAME);
        metadata.setRelativePath(getEapiRelativePath(path));

        FileService fileService = SpringBeanUtils.getBean(FileService.class);
        // 如果该路径上不存在api文件夹则直接创建新的api文件夹
        if (!fileService.isDirectoryExist(metadata.getRelativePath())) {
            fileService.createDirectory(metadata.getRelativePath());
        }
        return metadata;
    }

    private String getResourceType(ResourceType resourceType) {
        switch (resourceType) {
            case VO_ADVANCE:
                return EAPI_RESOURCE_TYPE_VO;
            case VO_SIMPLE:
                return EAPI_RESOURCE_TYPE_VO_SIMPLE;
            default:
                throw new RuntimeException("不支持的资源类型:" + resourceType);
        }
    }

    private String getEapiRelativePath(String path) {
        MetadataProject metadataProject = MetadataUtils.getMetadataProject(path);
        // 拼接eapi元数据路径:工程路径+eapi文件路径（/eapi）
        return metadataProject.getProjectPath() + EAPI_PATH;
    }

}
